#![allow(unused)]

use std::ffi::CString;

// 允许未使用的代码或变量
mod demo1;
mod demo2;
mod variables;
mod base_type;
/* 结构体
    结构体是Rust中创建自定义数据类型的基础
    结构体可以包含任何类型的数据，包括基本类型，数组，元组，结构体等
    结构体可以作为枚举的成员，也可以作为函数的参数和返回值

    使用时需要实例化
    let my_instance = MyStruct { e: 42 }; // 创建实例并初始化字段
*/
struct Struct {
    e: i32,
}

fn main() {
    // demo1::demo1();
    // demo2::demo2();
    // variables::demo();
    // main1();
    // 变量解构();
    // 解构式赋值();
    // 变量遮蔽();
    base_type::base_type_main();
}

fn main1() {
    let _x: i32 = 10;
    let y: i32 = 5;
    println!("Hello, world!")
}

fn 变量解构() {
    let (a, mut b): (bool, bool) = (true, false);
    // a = true, 不可变; b = false, 可变
    println!("a = {}, b = {}", a, b);
    b = true;
    assert_eq!(a, b);
}

fn 解构式赋值() {
    let (a, b, c, d, e);
    (a, b) = (1, 2);
    // _ 代表匹配一个值，但是我们不关心具体的值是什么，因此没有使用一个变量名而是使用了 _
    [c, .., d, _] = [1, 2, 3, 4, 5];
    Struct { e, .. } = Struct { e: 5 };
    assert_eq!([1, 2, 1, 4, 5], [a, b, c, d, e]);
}

fn 常量差异() {
    /*
    变量的值不能更改可能让你想起其他另一个很多语言都有的编程概念：常量(constant)。与不可变变量一样，
    常量也是绑定到一个常量名且不允许更改的值，但是常量和变量之间存在一些差异：
        1. 常量不允许使用 mut。  常量不仅仅默认不可变，而且自始至终不可变，因为常量在编译完成后，已经确定它的值。
        2. 常量使用 const 关键字而不是 let 关键字来声明，并且值的类型必须标注。

    常量可以在任意作用域内声明，包括全局作用域，在声明的作用域内，常量在程序运行的整个过程中都有效。
        对于需要在多处代码共享一个不可变的值时非常有用，例如游戏中允许玩家赚取的最大点数或光速。
    在实际使用中，最好将程序中用到的硬编码值都声明为常量，对于代码后续的维护有莫大的帮助。
        如果将来需要更改硬编码的值，你也只需要在代码中更改一处即可。
    */

    // 下面是一个常量声明的例子，其常量名为 MAX_POINTS，值设置为 100,000
    const MAX_POINTS: u32 = 100_000;
    // Rust 常量的命名约定是全部字母都使用大写，并使用下划线分隔单词，另外对数字字面量可插入下划线以提高可读性
}

fn 变量可变性() {
    /*
    变量可变性
    Rust 的变量是 immutable 的，即默认情况下变量的值不能被改变。
    如果你需要改变一个变量的值，你需要使用 mut 关键字来声明这个变量为可变的。
    */
    let mut x = 5;
    println!("The value of x is: {}", x);
    x = 6;
    println!("The value of x is: {}", x);
    /*
    选择可变还是不可变，更多的还是取决于你的使用场景，
    例如不可变可以带来安全性，但是丧失了灵活性和性能（如果你要改变，就要重新创建一个新的变量，这里涉及到内存对象的再分配）。
    而可变变量最大的好处就是使用上的灵活性和性能上的提升。
    例如，
    在使用大型数据结构或者热点代码路径（被大量频繁调用）的情形下，在同一内存位置更新实例可能比复制并返回新分配的实例要更快。
    使用较小的数据结构时，通常创建新的实例并以更具函数式的风格来编写程序，可能会更容易理解，所以值得以较低的性能开销来确保代码清晰。
    */

}
fn 变量遮蔽() {
    /*
    变量遮蔽
    变量遮蔽允许你使用相同的名称声明多个变量，只要它们在作用域内声明的顺序不同即可。
    变量遮蔽在变量声明时使用 let 关键字，并使用一个新变量名来声明变量，
    然后使用一个等号来赋值一个变量，这个变量可以是另一个变量，也可以是任何表达式。
    */

    let x = 5;

    // 在该函数的作用域内对之前的 x 进行遮蔽
    let x = x + 1;

    {
        // 在当前的花括号作用域内，对之前的x进行遮蔽
        let x = x * 2;
        println!("The value of xin the inner scope is: {}", x);
    }
    println!("The value of x is: {}", x);
    /*
    这个程序首先将数值 5 绑定到 x，
    然后通过重复使用 let x = 来遮蔽之前的 x，并取原来的值加上 1，所以 x 的值变成了 6。
    第三个 let 语句同样遮蔽前面的 x，取之前的值并乘上 2，得到的 x 最终值为 12。
    最后，在第一个 let 语句的作用域内打印出 x 的值为 6。
    */

    // 字符串类型
    let spaces = "   ";;
    // usize数值类型
    let spaces = spaces.len();

}
